/**
 * Copyright  2025, Hai Yue Xing He Technology Co., Ltd
 * 
 * @author          ZHAO LIMIN
 * @version         1.0.1
 * @since           2025-04
 * HYXHPointsCollection.ts     标准类，用于记录矢量图：PointsCollection 是点集合，在MultiPoints、Polygon、Polyline 中应用
 */

import { ICartesian } from "./Cartesian";
import { Cartesian3 } from "./Cartesian3";
import { Check } from "./Check";
import { defined } from "./Defined";
import { DeveloperError } from "./DeveloperError";
import { UNION_NUMBER_ARRAY } from "./HDataType";
import { GetSegmentPoints, GetSplitPointsForDistance } from "./HYXHGeo";
import { HYXHMathUtil } from "./HYXHMathUtil";

/**
 * 点的集合，不属于任何矢量图，及不进行任何的渲染
 * 用于记录点的集合，在MultiPoints、Polygon、Polyline 中应用
 */
export class PointsCollection {
    pointsCollection : Array<ICartesian>;
    constructor(){
        this.pointsCollection = new Array<ICartesian>();
    }

    /**
     * 批量添加点
     * @param points 点的集合 
     */
    public push(...points: ICartesian[]): void {
        for (let point of points) {
            this.pointsCollection.push(point);
        } 
    }
    /**
     * 获取点
     */
    public get points(): Array<ICartesian> {
        return this.pointsCollection;
    }

    public get length(): number {
        return defined(this.pointsCollection)?this.pointsCollection.length: 0; 
    }

    /**
     * 将点集合打包到数组中
     * @param array 
     * @param startIndex 
     */
    pack(array: UNION_NUMBER_ARRAY, startIndex: number):[number, UNION_NUMBER_ARRAY]
    {    Check.defined('array', array)
        if (!defined(array)) {
            array = new Array<number>(); 
        }
        if (startIndex < 0) {
            startIndex = 0;
        }
        let count = 0;
        for (let element of this.pointsCollection) { 
            if (!defined(element)) {
                continue;
            }
            Cartesian3.pack(element, array, startIndex);
            startIndex += Cartesian3.packedLength;
            count += Cartesian3.packedLength;
        }
        return [count, array];
    }

    unpack(array: UNION_NUMBER_ARRAY, startIndex: number): number {
        Check.defined('array', array);
        if (startIndex < 0) {
            startIndex = 0;
        }
        let count = 0;
        let index_cursor = startIndex;
        while( index_cursor < array.length ) {
            let element = new Cartesian3(
                array[index_cursor++],
                array[index_cursor++],
                array[index_cursor++]
            );
            this.pointsCollection.push(element);
            count++;
        }       
        return count;
    }

    public equals(other: PointsCollection): boolean {
        if (!defined(other)) {
            return false; 
        }
        if (this.length !== other.length) {
            return false; 
        }
        let _step = 0;
        let _cursor_i = 0;
        let _cursor_j = 0;
        while (_cursor_i < this.length) {
            const element = this.pointsCollection[_cursor_i];
            if (!defined(element)) {
                _cursor_i++;
                continue;
            }
            let start = false;
            for (let element2 of other.pointsCollection) {
                if (!defined(element2)) {
                    _cursor_j++;
                    continue;
                }
                if (Cartesian3.equalsEpsilon(element, element2, HYXHMathUtil.EPSILON2)) {
                    start = true;
                    break;
                }
                _cursor_j++;
            }
            if (start) {
                break;
            }
            if ( _cursor_j >= this.length){
                return false;
            }
        }

        while ((_cursor_i < this.length)  && (_cursor_j < other.length)){
            const element = this.pointsCollection[_cursor_i];
            if (!defined(element)) {
                return false;
            }

            const element2 = other.pointsCollection[_cursor_j];
            if (!defined(element2)) {
                return false;
            }

            if (!Cartesian3.equalsEpsilon(element, element2, HYXHMathUtil.EPSILON2)) {
                return false;
            }
            _cursor_i++;
            /* 循环比较 */
            if (_cursor_i >= this.length) {
                _cursor_i = 0;
            }
            _cursor_j++;
            if (_cursor_j >= other.length) {
                _cursor_j = 0;
            }
            _step++;
            if (_step >= this.length) {
                return true;
            }
        }
        return true;
    }

    public generateToLinesIndices(layer: number): UNION_NUMBER_ARRAY {
        if ( this.length < 2) {
            throw new DeveloperError("PointsCollection 中的点的数量小于2");
        }
        let indices = new Array<number>();
        for (let i = 0; i < this.length - 1; i++) {
            indices.push(layer);
            indices.push(i);
            indices.push(layer);
            indices.push(i + 1);
        }
        return indices;
    }

    public getPoint(index: number): ICartesian {
        if (index < 0 || index >= this.length) {
            throw new DeveloperError("索引超出范围");
        }
        return this.pointsCollection[index]; 
    }

    /**
     * 按照指定断落数，进行插值，返回插值后的点的数组
     * @param segmentCount 段落
     */
    public interpolationForStraightLine(segmentCount: number): Array<ICartesian> {
        Check.defined("segmentCount", segmentCount);
        Check.defined("pointsCollection", this.pointsCollection);
        if (segmentCount < 2) {
            throw new DeveloperError("segmentCount 必须大于等于2"); 
        }
        if (this.length < 2) {
            throw new DeveloperError("PointsCollection 中的点的数量小于2");
        }
        let points = new Array<ICartesian>();
        let curosr_index = 0;
        let start = null;
        let end = null;
        while (curosr_index < this.length - 1) {
            start = this.pointsCollection[curosr_index];
            end = this.pointsCollection[curosr_index + 1];
            let segmentPoints = GetSegmentPoints(start, end, segmentCount);
            points.push(start);           
            if (segmentPoints.length > 0) {
                points.push(...segmentPoints);
            } 
            curosr_index++;
        }
        if (defined(end)) {
            points.push(end);  
        }
        
        this.pointsCollection.splice(0, this.pointsCollection.length -1);
        this.pointsCollection.length = 0;
        this.pointsCollection.push(...points);
        return points;
    }

    public interpolationDistForStraightLine(distance: number): Array<ICartesian> {
        Check.defined("segmentCount", distance);
        Check.defined("pointsCollection", this.pointsCollection);
        if (this.length < 2) {
            throw new DeveloperError("PointsCollection 中的点的数量小于2");
        }
        let points = new Array<ICartesian>();
        let curosr_index = 0;
        let start = null;
        let end = null;
        while (curosr_index < this.length - 1) {
            start = this.pointsCollection[curosr_index];
            end = this.pointsCollection[curosr_index + 1];
            let segmentPoints = GetSplitPointsForDistance(start, end, distance);
            points.push(start);           
            if (segmentPoints.length > 0) {
                points.push(...segmentPoints);
            }            
            curosr_index++;
        }
        if (defined(end)) {
            points.push(end);  
        }

        this.pointsCollection.splice(0, this.pointsCollection.length);
        this.pointsCollection.length = 0;
        this.pointsCollection.push(...points);
        return points;
    }

    public multiplyComponents(scale: ICartesian): void {
        if (!defined(scale)) {
            throw new DeveloperError("scale 未定义"); 
        }
        for (let element of this.pointsCollection) {
            if (!defined(element)) {
                continue;
            }
            Cartesian3.multiplyComponents(element, scale, element);
        }
    }
    /**偏移 */
    public add(rotation: ICartesian): void {
        if (!defined(rotation)) {
            throw new DeveloperError("rotation 未定义"); 
        }
        for (let element of this.pointsCollection) {
            if (!defined(element)) {
                continue;
            }
            Cartesian3.add(element, rotation, element);
        }
    }

    public find(position: ICartesian): Array<number> {
        Check.defined("position",position);
        Check.defined("pointsCollection", this.pointsCollection);
        if ( this.pointsCollection.length <= 0) {
            throw new DeveloperError("Point Collection is empty");
        }
        for (let i = 0; i < this.length - 1; i++) {
            const _point = this.pointsCollection[i];
            if (!defined(_point)){
                continue;
            }
            if ( Cartesian3.equalsEpsilon(_point, position, HYXHMathUtil.EPSILON1)) {
                return [i];
            } 
        }
        return [];
    }
}